
/****************************************************************************/
/*Copyright (c) 2011, Florent DEVILLE.                                      */
/*All rights reserved.                                                      */
/*                                                                          */
/*Redistribution and use in source and binary forms, with or without        */
/*modification, are permitted provided that the following conditions        */
/*are met:                                                                  */
/*                                                                          */
/* - Redistributions of source code must retain the above copyright         */
/*notice, this list of conditions and the following disclaimer.             */
/* - Redistributions in binary form must reproduce the above                */
/*copyright notice, this list of conditions and the following               */
/*disclaimer in the documentation and/or other materials provided           */
/*with the distribution.                                                    */
/* - The names of its contributors cannot be used to endorse or promote     */
/*products derived from this software without specific prior written        */
/*permission.                                                               */
/* - The source code cannot be used for commercial purposes without         */ 
/*its contributors' permission.                                             */
/*                                                                          */
/*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       */
/*"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         */
/*LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS         */
/*FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE            */
/*COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,       */
/*INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,      */
/*BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;          */
/*LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER          */
/*CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT        */
/*LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN         */
/*ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
/*POSSIBILITY OF SUCH DAMAGE.                                               */
/****************************************************************************/

#include "RTSceneLoader.h"


#include <tinyxml.h>
#include "RTScene.h"


#include "RTRaytracer.h"


#include <sstream>
using std::stringstream;

#include <iostream>
using std::cout;
using std::endl;

//lights
#include "RTPointLight.h"
#include "RTDirectionalLight.h"
#include "RTSpotLight.h"

//RTPrimitives
#include "RTPrimPlan.h"
#include "RTPrimSphere.h"
#include "RTPrimCylinder.h"
#include "RTPrimCone.h"
#include "RTPrimTore.h"
#include "RTPrimTriangle.h"
#include "RTPrimBox.h"
#include "RTPrimCSG.h"

#include "RTMatrix44.h"

#include "RTProcTextureChecker.h"
#include "RTProcTextureWood.h"
#include "RTProcTextureMarble.h"
#include "RTProcTextureThreshold.h"
#include "RTProcTextureBump.h"

#include "RTCSGNode.h"
#include "RTBooleanType.h"

#include "RTMaterial.h"

namespace RT
{

	RTSceneLoader::RTSceneLoader(){}

	bool RTSceneLoader::load(const string& filename)
	{
		//open the xml document
		TiXmlDocument doc;
		if(!doc.LoadFile(filename.c_str()))
			return false;

		m_filename = filename;

		//check if the root is valid
		TiXmlElement* root = doc.RootElement();
		string nodeName = root->Value();
		if(nodeName.compare("Raytracer")!=0)
			return false;

		//get the first child
		TiXmlElement* currentNode = root->FirstChildElement();

		//go throught the xml
		while(currentNode != 0)
		{
			nodeName = currentNode->Value();

			if(nodeName.compare("Scene") == 0)
				loadScene(currentNode);
			else if (nodeName.compare("Configuration") == 0)
				loadConfiguration(currentNode);

			currentNode = currentNode->NextSiblingElement();
		}

		return true;
	}


	void RTSceneLoader::loadConfiguration(TiXmlElement* config)const
	{
		//get the first child
		TiXmlElement* currentNode = config->FirstChildElement();

		while(currentNode != 0)
		{
			string name = currentNode->Value();

			if(name.compare("RatioAndFoV") == 0)
			{
				RTVector3f p;
				getVector3(currentNode, p);

				RAYTRACER.setScreen(p.x, p.y, p.z);
			}
			else if (name.compare("Resolution") == 0)
			{
				I32 w, h;
				stringstream ss;
				ss<<currentNode->GetText();
				ss>>w;
				ss>>h;
			
				RAYTRACER.setResolution(w, h);
			}
			else if(name.compare("OversamplingLevel") == 0)
			{
				I32 level = 0;
				stringstream ss;
				ss<<currentNode->GetText();
				ss>>level;

				switch(level)
				{
				case 0:
					RAYTRACER.setOverSampling(RTRaytracer::NO_OVERSAMPLING);
					break;
				case 1:
					RAYTRACER.setOverSampling(RTRaytracer::LVL1_OVERSAMPLING);
					break;
				case 2:
					RAYTRACER.setOverSampling(RTRaytracer::LVL2_OVERSAMPLING);
					break;

				default:
					RAYTRACER.setOverSampling(RTRaytracer::NO_OVERSAMPLING);
				}

			}

			//get next node
			currentNode = currentNode->NextSiblingElement();
		}
	}

	void RTSceneLoader::loadScene(TiXmlElement* scene)const
	{
		//get the first child
		TiXmlElement* currentNode = scene->FirstChildElement();

		//go throught the xml
		while(currentNode != 0)
		{
			string nodeName = currentNode->Value();

			if(nodeName.compare("Lights") == 0)
				loadLights(currentNode);
			else if (nodeName.compare("Materials") == 0)
				loadMaterials(currentNode);
			else if(nodeName.compare("Objects") == 0)
				loadObjects(currentNode);

			currentNode = currentNode->NextSiblingElement();
		}
	}

	void RTSceneLoader::loadLights(TiXmlElement* light)const
	{
		//storage variables
		RTVector3f position, direction, attenuation;
		RTColor color;
		F32 cutOff = 0;
		F32 beam = 0;

		//get the first light
		TiXmlElement* currentLight = light->FirstChildElement();

		//for every light
		while(currentLight != 0)
		{
			//get the light name
			string nodeName = currentLight->Value();

			//if poI32 light
			if(nodeName.compare("PoI32Light") == 0)
			{
				TiXmlElement* parameter = currentLight->FirstChildElement();
			
				while(parameter != 0)
				{
					string paramName = parameter->Value();
					if(paramName.compare("Position") == 0)
						getVector3(parameter, position);
					else if (paramName.compare("Color") == 0)
						getVector3(parameter, color);
					else if (paramName.compare("Attenuation") == 0)
						getVector3(parameter, attenuation);

					//get next parameter
					parameter = parameter->NextSiblingElement();
				}

				//add light
				RTSCENE.addLight(new RTPointLight(position, color, attenuation));
			}
			//if directional
			else if (nodeName.compare("DirectionalLight") == 0)
			{
				TiXmlElement* parameter = currentLight->FirstChildElement();
			
				while(parameter != 0)
				{
					string paramName = parameter->Value();
					if(paramName.compare("Direction") == 0)//store the idrection on the position
						getVector3(parameter, direction);
					else if (paramName.compare("Color") == 0)
						getVector3(parameter, color);
					//get next parameter
					parameter = parameter->NextSiblingElement();
				}

				//add light
				RTSCENE.addLight(new RTDirectionalLight(color, direction));
			}
			//if spot
			else if (nodeName.compare("SpotLight") == 0)
			{
				TiXmlElement* parameter = currentLight->FirstChildElement();
			
				while(parameter != 0)
				{
					string paramName = parameter->Value();
					if(paramName.compare("Position") == 0)//store the idrection on the position
						getVector3(parameter, position);
					else if (paramName.compare("Color") == 0)
						getVector3(parameter, color);
					else if(paramName.compare("Direction") == 0)
						getVector3(parameter, direction);
					else if(paramName.compare("Attenuation") == 0)
						getVector3(parameter, attenuation);
					else if(paramName.compare("CutOff") == 0)
						cutOff = getFloat(parameter);
					else if(paramName.compare("Beam") == 0)
						beam = getFloat(parameter);
					//get next parameter
					parameter = parameter->NextSiblingElement();
				}

				//add light
				RTSCENE.addLight(new RTSpotLight(color, position, direction, cutOff, beam, attenuation));
			}

			//get the next light
			currentLight = currentLight->NextSiblingElement();
		}
	}

	void RTSceneLoader::loadMaterials(TiXmlElement* material)const
	{
		//get the first material
		TiXmlElement* currentMaterial = material->FirstChildElement();

		//for every material
		while(currentMaterial != 0)
		{
			//get the material name
			string matName = currentMaterial->Attribute("name");
			if(RTSCENE.getMaterial(matName) != 0)
			{
				cout<<"ERROR MATERIAL : "<<matName<<endl;
				currentMaterial = currentMaterial->NextSiblingElement();
				continue;
			}
		
			//create the material
			RTMaterial* material = new RTMaterial();

			//get the parameters
			TiXmlElement* parameter = currentMaterial->FirstChildElement();
			while(parameter != 0)
			{
				RTColor color;
				string parameterName = parameter->Value();
				if(parameterName.compare("Diffuse") == 0)
				{
					RTColor d;
					getVector3(parameter, d);
					material->setDiffuse(d);
				}
				//else if(parameterName.compare("Ambient") == 0)
				//	getVector3(parameter, material->m_ambient);
				/*else if(parameterName.compare("Specular") == 0)
					getVector3(parameter, material->m_specular);*/
				else if(parameterName.compare("Reflect") == 0)
					getVector3(parameter, material->m_reflect);
				else if(parameterName.compare("Shininess") == 0)
					material->m_shininess = getFloat(parameter);
				else if(parameterName.compare("Refraction") == 0)
					material->m_refractionIndex = getFloat(parameter);
				//else if(parameterName.compare("Transparancy") == 0)
				//	material->m_transparancyCoef = getFloat(parameter);
				else if(parameterName.compare("ProceduralTexture") == 0)
				{
					string procTextName = parameter->Attribute("type");
					if(procTextName.compare("Checker") == 0)
						loadProcTextureChecker(parameter, material);
					else if(procTextName.compare("Wood") == 0)
						loadProcTextureWood(parameter, material);
					else if(procTextName.compare("Marble") == 0)
						loadProcTextureMarble(parameter, material);
					else if(procTextName.compare("Threshold") == 0)
						loadProcTextureThreshold(parameter, material);
					else if(procTextName.compare("Bump") == 0)
						loadProcTextureBump(parameter, material);
				}

				parameter = parameter->NextSiblingElement();
			}
		
			//add the material
			RTSCENE.addMaterial(material, matName);

			//get the next material
			currentMaterial = currentMaterial->NextSiblingElement();
		}
	}

	void RTSceneLoader::loadObjects(TiXmlElement* object)const
	{
		//get the first object
		TiXmlElement* currentObject = object->FirstChildElement();

		//for every object
		while(currentObject != 0)
		{
			//get the object type
			string objectType = currentObject->Attribute("type");

			//store the objects
			RTIPrimitive* object = 0;

			if(objectType.compare("Plan") == 0)
				object = loadGeometryPlan(currentObject);
			else if(objectType.compare("Sphere") == 0)
				object = loadGeometrySphere(currentObject);
			else if(objectType.compare("Cylinder") == 0)
				object = loadGeometryCylinder(currentObject);
			else if(objectType.compare("Cone") == 0)
				object = loadGeometryCone(currentObject);
			else if(objectType.compare("Torus") == 0)
				object = loadGeometryTorus(currentObject);
			else if(objectType.compare("Camera") == 0)
				loadGeometryCamera(currentObject);
			else if(objectType.compare("Triangle") == 0)
				object = loadGeometryTriangle(currentObject);
			else if(objectType.compare("Box") == 0)
				object = loadGeometryBox(currentObject);
			else if(objectType.compare("CSG") == 0)
				object = loadGeometryCSG(currentObject);
			else if(objectType.compare("FromFile") == 0)
				object = loadGeometryFromFile(currentObject);
		
			//get the next object
			currentObject = currentObject->NextSiblingElement();

			//add the object to the scene
			if(object != 0)
				RTSCENE.addPrimitive(object);
		
		}
	}

	RTIPrimitive* RTSceneLoader::loadModelFile(const string& filename)const
	{
		//open the xml document
		TiXmlDocument doc;
		if(!doc.LoadFile(filename.c_str()))
			return false;

		//check if the root is valid
		TiXmlElement* root = doc.RootElement();
		string nodeName = root->Value();
		if(nodeName.compare("Model")!=0)
			return false;

		//get the first child
		TiXmlElement* currentNode = root->FirstChildElement();
	
		RTIPrimitive* RTPrimitive = 0;

		//go throught the xml
		while(currentNode != 0)
		{
			nodeName = currentNode->Value();

			if(nodeName.compare("Materials") == 0)
				loadMaterials(currentNode);
			else if (nodeName.compare("Objects") == 0)
			{
				TiXmlElement* child = currentNode->FirstChildElement();

				//get the type of RTPrimitive
				string objectType = child->Attribute("type");

				//load the RTPrimitive
				if(objectType.compare("Plan") == 0)
					RTPrimitive = loadGeometryPlan(child);
				else if(objectType.compare("Sphere") == 0)
					RTPrimitive = loadGeometrySphere(child);
				else if(objectType.compare("Cylinder") == 0)
					RTPrimitive = loadGeometryCylinder(child);
				else if(objectType.compare("Cone") == 0)
					RTPrimitive = loadGeometryCone(child);
				else if(objectType.compare("Torus") == 0)
					RTPrimitive = loadGeometryTorus(child);
				else if(objectType.compare("Triangle") == 0)
					RTPrimitive = loadGeometryTriangle(child);
				else if(objectType.compare("Box") == 0)
					RTPrimitive = loadGeometryBox(child);
				else if(objectType.compare("CSG") == 0)
					RTPrimitive = loadGeometryCSG(child);
			}

			currentNode = currentNode->NextSiblingElement();
		}

		return RTPrimitive;
	}

	void RTSceneLoader::loadGeometryCamera(TiXmlElement* element)const
	{
		//get the first parameter
		TiXmlElement* parameter = element->FirstChildElement();

		//create the camera vectors
		RTVector3f eye, at, up;

		//for every parameter
		while(parameter != 0)
		{
			//get the param type
			string paramName = parameter->Value();

			if(paramName.compare("Eye") == 0)
				getVector3(parameter, eye);
			else if(paramName.compare("At") == 0)
				getVector3(parameter, at);
			else if(paramName.compare("Up") == 0)
				getVector3(parameter, up);
		
			//get next parameter
			parameter = parameter->NextSiblingElement();
		}

		//set camera
		RAYTRACER.setViewer(eye, at, up);
	}

	RTIPrimitive* RTSceneLoader::loadGeometryPlan(TiXmlElement* element)const
	{
		//get the first parameter
		TiXmlElement* parameter = element->FirstChildElement();

		//set matrices
		RTMatrix44 TMatrix, RMatrix, S;
		TMatrix.identity();
		RMatrix.identity();
		S.identity();

		//creat the three poI32s representing the plan
		RTVector3f P1, P2, P3;

		//poI32er to the material
		RTMaterial* material = 0;

		//for every parameter
		while(parameter != 0)
		{
			//get the param type
			string paramName = parameter->Value();

			RTMatrix44 tempMatrix;
			tempMatrix.identity();
			if(paramName.compare("Rotate") == 0)
			{
				loadTransformRotation(parameter, tempMatrix);
				RMatrix = RMatrix * tempMatrix;
			}
			else if(paramName.compare("Translate") == 0)
			{
				loadTransformTranslate(parameter, tempMatrix);
				TMatrix = TMatrix * tempMatrix;
			}
			else if(paramName.compare("Scale") == 0)
			{
				loadTransformScale(parameter, tempMatrix);
				S = S * tempMatrix;
			}
			else if(paramName.compare("Model") == 0)
			{
				//get plan model
				string model = parameter->GetText();
			
				if(model.compare("xOy") == 0)
				{
					P1 = RTVector3f(0, 0, 0);
					P2 = RTVector3f(1, 0, 0);
					P3 = RTVector3f(1, 1, 0);
				}
				else if (model.compare("xOz") == 0)
				{
					P1 = RTVector3f(0, 0, 0);
					P2 = RTVector3f(1, 0, 0);
					P3 = RTVector3f(1, 0, -1);
				}
				else if(model.compare("yOz") == 0)
				{
					P1 = RTVector3f(0, 0, 0);
					P2 = RTVector3f(0, 1, 0);
					P3 = RTVector3f(0, 1, 1);
				}

			}
			else if(paramName.compare("Material") == 0)
			{
				string nameMaterial = parameter->GetText();
				material = RTSCENE.getMaterial(nameMaterial);
			}

			parameter = parameter->NextSiblingElement();
		}

		//create the plan
		RTPrimPlan* plan = new RTPrimPlan(P1, P2, P3);
		plan->setMaterial(material);
		plan->setMatrices(TMatrix, RMatrix, S);
		return plan;
		//SCENE.addPrimitive(plan);
	}

	RTIPrimitive* RTSceneLoader::loadGeometrySphere(TiXmlElement* element)const
	{
		//get the first parameter
		TiXmlElement* parameter = element->FirstChildElement();

		//set matrices
		RTMatrix44 TMatrix, RMatrix, S;
		TMatrix.identity();
		RMatrix.identity();
		S.identity();

		//creat the three poI32s representing the sphere
		RTVector3f center;
		F32 radius = 0;

		//poI32er to the material
		RTMaterial* material = 0;

		//for every parameter
		while(parameter != 0)
		{
			//get the param type
			string paramName = parameter->Value();

			RTMatrix44 tempMatrix;
			tempMatrix.identity();

			if(paramName.compare("Rotate") == 0)
			{
				loadTransformRotation(parameter, tempMatrix);
				RMatrix = RMatrix * tempMatrix;
			}
			else if(paramName.compare("Translate") == 0)
			{
				loadTransformTranslate(parameter, tempMatrix);
				TMatrix = TMatrix * tempMatrix;
			}
			else if(paramName.compare("Scale") == 0)
			{
				loadTransformScale(parameter, tempMatrix);
				S = S * tempMatrix;
			}
			else if(paramName.compare("Radius") == 0)
			{
				radius = getFloat(parameter);
			}
			else if(paramName.compare("Material") == 0)
			{
				string nameMaterial = parameter->GetText();
				material = RTSCENE.getMaterial(nameMaterial);
			}

			parameter = parameter->NextSiblingElement();
		}

		//create the sphere
		RTPrimSphere* sphere = new RTPrimSphere(radius);
		sphere->setMaterial(material);
		sphere->setMatrices(TMatrix, RMatrix, S);
		return sphere;
		//SCENE.addPrimitive(sphere);
	}

	RTIPrimitive* RTSceneLoader::loadGeometryCylinder(TiXmlElement* element)const
	{
		//get the first parameter
		TiXmlElement* parameter = element->FirstChildElement();

		//set matrices
		RTMatrix44 TMatrix, RMatrix, S;
		TMatrix.identity();
		RMatrix.identity();
		S.identity();

		//cradius and height
		F32 height = 0;
		F32 radius = 0;

		//poI32er to the material
		RTMaterial* material = 0;

		//for every parameter
		while(parameter != 0)
		{
			//get the param type
			string paramName = parameter->Value();

			RTMatrix44 tempMatrix;
			tempMatrix.identity();

			if(paramName.compare("Rotate") == 0)
			{
				loadTransformRotation(parameter, tempMatrix);
				RMatrix = RMatrix * tempMatrix;
			}
			else if(paramName.compare("Translate") == 0)
			{
				loadTransformTranslate(parameter, tempMatrix);
				TMatrix = TMatrix * tempMatrix;
			}
			else if(paramName.compare("Scale") == 0)
			{
				loadTransformScale(parameter, tempMatrix);
				S = S * tempMatrix;
			}
			else if(paramName.compare("Height") == 0)
			{
				height = getFloat(parameter);
			}
			else if(paramName.compare("Radius") == 0)
			{
				radius = getFloat(parameter);
			}
			else if(paramName.compare("Material") == 0)
			{
				string nameMaterial = parameter->GetText();
				material = RTSCENE.getMaterial(nameMaterial);
			}

			parameter = parameter->NextSiblingElement();
		}

		//create the cylinder
		RTPrimCylinder* cylinder = new RTPrimCylinder(radius, height);
		cylinder->setMaterial(material);
		cylinder->setMatrices(TMatrix, RMatrix, S);
		return cylinder;
		//SCENE.addPrimitive(cylinder);
	}

	RTIPrimitive* RTSceneLoader::loadGeometryCone(TiXmlElement* element)const
	{
		//get the first parameter
		TiXmlElement* parameter = element->FirstChildElement();

		//set matrices
		RTMatrix44 TMatrix, RMatrix, S;
		TMatrix.identity();
		RMatrix.identity();
		S.identity();

		//radius and height
		F32 height = 0;
		F32 radius = 0;

		//poI32er to the material
		RTMaterial* material = 0;

		//for every parameter
		while(parameter != 0)
		{
			//get the param type
			string paramName = parameter->Value();

			RTMatrix44 tempMatrix;
			tempMatrix.identity();

			if(paramName.compare("Rotate") == 0)
			{
				loadTransformRotation(parameter, tempMatrix);
				RMatrix = RMatrix * tempMatrix;
			}
			else if(paramName.compare("Translate") == 0)
			{
				loadTransformTranslate(parameter, tempMatrix);
				TMatrix = TMatrix * tempMatrix;
			}
			else if(paramName.compare("Scale") == 0)
			{
				loadTransformScale(parameter, tempMatrix);
				S = S * tempMatrix;
			}
			else if(paramName.compare("Height") == 0)
			{
				height = getFloat(parameter);
			}
			else if(paramName.compare("Radius") == 0)
			{
				radius = getFloat(parameter);
			}
			else if(paramName.compare("Material") == 0)
			{
				string nameMaterial = parameter->GetText();
				material = RTSCENE.getMaterial(nameMaterial);
			}

			parameter = parameter->NextSiblingElement();
		}

		//create the cylinder
		RTPrimCone* cone = new RTPrimCone(radius, height);
		cone->setMaterial(material);
		cone->setMatrices(TMatrix, RMatrix, S);
		return cone;
		//SCENE.addPrimitive(cone);
	}

	RTIPrimitive* RTSceneLoader::loadGeometryTorus(TiXmlElement* element)const
	{
		//get the first parameter
		TiXmlElement* parameter = element->FirstChildElement();

		//set matrices
		RTMatrix44 TMatrix, RMatrix, S;
		TMatrix.identity();
		RMatrix.identity();
		S.identity();

		//radius and height
		F32 br = 0;
		F32 sr = 0;

		//poI32er to the material
		RTMaterial* material = 0;

		//for every parameter
		while(parameter != 0)
		{
			//get the param type
			string paramName = parameter->Value();

			RTMatrix44 tempMatrix;
			tempMatrix.identity();

			if(paramName.compare("Rotate") == 0)
			{
				loadTransformRotation(parameter, tempMatrix);
				RMatrix = RMatrix * tempMatrix;
			}
			else if(paramName.compare("Translate") == 0)
			{
				loadTransformTranslate(parameter, tempMatrix);
				TMatrix = TMatrix * tempMatrix;
			}
			else if(paramName.compare("Scale") == 0)
			{
				loadTransformScale(parameter, tempMatrix);
				S = S * tempMatrix;
			}
			else if(paramName.compare("BigRadius") == 0)
			{
				br = getFloat(parameter);
			}
			else if(paramName.compare("SmallRadius") == 0)
			{
				sr = getFloat(parameter);
			}
			else if(paramName.compare("Material") == 0)
			{
				string nameMaterial = parameter->GetText();
				material = RTSCENE.getMaterial(nameMaterial);
			}

			parameter = parameter->NextSiblingElement();
		}

		//create the torus
		RTPrimTore* tore = new RTPrimTore(br, sr);
		tore->setMaterial(material);
		tore->setMatrices(TMatrix, RMatrix, S);
		return tore;
		//SCENE.addPrimitive(tore);
	}

	RTIPrimitive* RTSceneLoader::loadGeometryTriangle(TiXmlElement* element)const
	{
		//get the first parameter
		TiXmlElement* parameter = element->FirstChildElement();

		//store the 3 poI32s
		RTVector3f P[3];

		//set matrices
		RTMatrix44 TMatrix, RMatrix, S;
		TMatrix.identity();
		RMatrix.identity();
		S.identity();

		//poI32er to the material
		RTMaterial* material = 0;

		//for every parameter
		while(parameter != 0)
		{
			//get the param type
			string paramName = parameter->Value();

			RTMatrix44 tempMatrix;
			tempMatrix.identity();

			if(paramName.compare("Rotate") == 0)
			{
				loadTransformRotation(parameter, tempMatrix);
				RMatrix = RMatrix * tempMatrix;
			}
			else if(paramName.compare("Translate") == 0)
			{
				loadTransformTranslate(parameter, tempMatrix);
				TMatrix = TMatrix * tempMatrix;
			}
			else if(paramName.compare("Scale") == 0)
			{
				loadTransformScale(parameter, tempMatrix);
				S = S * tempMatrix;
			}
			else if(paramName.compare("PoI32") == 0)
			{
				//get the text in a stringstream
				stringstream ss;
				ss<<parameter->GetText();

				//create the poI32
				ss>>P[0].x; ss>>P[0].y; ss>>P[0].z;
				ss>>P[1].x; ss>>P[1].y; ss>>P[1].z;
				ss>>P[2].x; ss>>P[2].y; ss>>P[2].z;
			}
			else if(paramName.compare("Material") == 0)
			{
				string nameMaterial = parameter->GetText();
				material = RTSCENE.getMaterial(nameMaterial);
			}

			parameter = parameter->NextSiblingElement();
		}

		//create the triangle
		RTPrimTriangle* triangle = new RTPrimTriangle(P);
		triangle->setMaterial(material);
		triangle->setMatrices(TMatrix, RMatrix, S);
		return triangle;
		//SCENE.addPrimitive(triangle);
	}

	RTIPrimitive* RTSceneLoader::loadGeometryBox(TiXmlElement* element)const
	{
		//get the first parameter
		TiXmlElement* parameter = element->FirstChildElement();

		//store the box dimension
		RTVector3f dimension;

		//set matrices
		RTMatrix44 TMatrix, RMatrix, S;
		TMatrix.identity();
		RMatrix.identity();
		S.identity();

		//poI32er to the material
		RTMaterial* material = 0;

		//for every parameter
		while(parameter != 0)
		{
			//get the param type
			string paramName = parameter->Value();

			RTMatrix44 tempMatrix;
			tempMatrix.identity();

			if(paramName.compare("Rotate") == 0)
			{
				loadTransformRotation(parameter, tempMatrix);
				RMatrix = RMatrix * tempMatrix;
			}
			else if(paramName.compare("Translate") == 0)
			{
				loadTransformTranslate(parameter, tempMatrix);
				TMatrix = TMatrix * tempMatrix;
			}
			else if(paramName.compare("Scale") == 0)
			{
				loadTransformScale(parameter, tempMatrix);
				S = S * tempMatrix;
			}
			else if(paramName.compare("Dimension") == 0)
			{
				getVector3(parameter, dimension);
			}
			else if(paramName.compare("Material") == 0)
			{
				string nameMaterial = parameter->GetText();
				material = RTSCENE.getMaterial(nameMaterial);
			}

			parameter = parameter->NextSiblingElement();
		}

		//create the box
		RTPrimBox* box = new RTPrimBox(dimension.x, dimension.y, dimension.z);
		box->setMaterial(material);
		box->setMatrices(TMatrix, RMatrix, S);
		return box;
		//SCENE.addPrimitive(box);
	}

	RTIPrimitive* RTSceneLoader::loadGeometryCSG(TiXmlElement* element)const
	{
		//get the first parameter
		TiXmlElement* parameter = element->FirstChildElement();

		//set matrices
		RTMatrix44 TMatrix, RMatrix, S;
		TMatrix.identity();
		RMatrix.identity();
		S.identity();

		//poI32er to the material
		RTMaterial* material = 0;

		//root
		RTCSGNode* root = 0;

		//for every parameter
		while(parameter != 0)
		{
			//get the param type
			string paramName = parameter->Value();

			RTMatrix44 tempMatrix;
			tempMatrix.identity();

			if(paramName.compare("Rotate") == 0)
			{
				loadTransformRotation(parameter, tempMatrix);
				RMatrix = RMatrix * tempMatrix;
			}
			else if(paramName.compare("Translate") == 0)
			{
				loadTransformTranslate(parameter, tempMatrix);
				TMatrix = TMatrix * tempMatrix;
			}
			else if(paramName.compare("Scale") == 0)
			{
				loadTransformScale(parameter, tempMatrix);
				S = S * tempMatrix;
			}
			else if(paramName.compare("Material") == 0)
			{
				string nameMaterial = parameter->GetText();
				material = RTSCENE.getMaterial(nameMaterial);
			}
			else if(paramName.compare("Node") == 0)
			{
				root = loadNodeCSG(parameter);
			}

			parameter = parameter->NextSiblingElement();
		}

		//create the box
		RTPrimCSG* csg = new RTPrimCSG(root);
		csg->setMaterial(material);
		csg->setMatrices(TMatrix, RMatrix, S);
		return csg;
		//SCENE.addPrimitive(csg);
	}

	RTCSGNode* RTSceneLoader::loadNodeCSG(TiXmlElement* element)const
	{
		//temp variables
		RTCSGNode* child1 = 0;
		RTCSGNode* child2 = 0;
		RTIPrimitive* RTPrimitive = 0;

		//get the type of node
		string nodeType = element->Attribute("type");
		eBoolType eNodeType = eBoolNone;
		if(nodeType.compare("Difference") == 0)
			eNodeType = eBoolDifference;
		else if(nodeType.compare("Intersection") == 0)
			eNodeType = eBoolIntersection;
		else if(nodeType.compare("Union") == 0)
			eNodeType = eBoolUnion;

		//get the fist child
		TiXmlElement* child = element->FirstChildElement();

		//go throught the children
		while(child != 0)
		{
			string nodeName = child->Value();

			//node
			if(nodeName.compare("Node") == 0)
			{
				if(child1 == 0)
					child1 = loadNodeCSG(child);
				else
					child2 = loadNodeCSG(child);
			}
			else if (nodeName.compare("Primitive") == 0)
			{
				//get the type of RTPrimitive
				string objectType = child->Attribute("type");

				//load the RTPrimitive
				if(objectType.compare("Plan") == 0)
					RTPrimitive = loadGeometryPlan(child);
				else if(objectType.compare("Sphere") == 0)
					RTPrimitive = loadGeometrySphere(child);
				else if(objectType.compare("Cylinder") == 0)
					RTPrimitive = loadGeometryCylinder(child);
				else if(objectType.compare("Cone") == 0)
					RTPrimitive = loadGeometryCone(child);
				else if(objectType.compare("Torus") == 0)
					RTPrimitive = loadGeometryTorus(child);
				else if(objectType.compare("Triangle") == 0)
					RTPrimitive = loadGeometryTriangle(child);
				else if(objectType.compare("Box") == 0)
					RTPrimitive = loadGeometryBox(child);
			}

			//get the next child
			child = child->NextSiblingElement();
		}

		//create the node
		RTCSGNode* node = new RTCSGNode(RTPrimitive, eNodeType, child1, child2);
		return node;
	

	}

	RTIPrimitive* RTSceneLoader::loadGeometryFromFile(TiXmlElement* element)const
	{
		//get the first parameter
		TiXmlElement* parameter = element->FirstChildElement();

		//set matrices
		RTMatrix44 T, R, S;
		T.identity(); R.identity(); S.identity();

		//RTPrimitive
		RTIPrimitive* prim = 0;

		//for every parameter
		while(parameter != 0)
		{
			//get the param type
			string paramName = parameter->Value();

			RTMatrix44 tempMatrix;
			tempMatrix.identity();

			if(paramName.compare("Rotate") == 0)
			{
				loadTransformRotation(parameter, tempMatrix);
				R = R * tempMatrix;
			}
			else if(paramName.compare("Translate") == 0)
			{
				loadTransformTranslate(parameter, tempMatrix);
				T = T * tempMatrix;
			}
			else if(paramName.compare("Scale") == 0)
			{
				loadTransformScale(parameter, tempMatrix);
				S = S * tempMatrix;
			}
			else if(paramName.compare("RTSource") == 0)
			{
				string sourceFile = parameter->GetText();
				prim = loadModelFile(sourceFile);
				if(!prim)
				{
					cout<<"Error during model loading : "<<sourceFile<<endl;
					system("pause");
					return false;
				}
			}

			parameter = parameter->NextSiblingElement();
		}

		//return the RTPrimitive
		prim->setMatrices(T, R, S);
		return prim;

	}

	void RTSceneLoader::loadTransformRotation(TiXmlElement* element, RTMatrix44& out)const
	{
		//get the axis
		string axis = element->Attribute("axis");
	
		//get the angle
		F32 theta = getFloat(element);

		//create the rotation matrix
		if(axis.compare("X")==0)
			out.createRotationX(theta);
		else if(axis.compare("Y")==0)
			out.createRotationY(theta);
		else if(axis.compare("Z")==0)
			out.createRotationZ(theta);
	}

	void RTSceneLoader::loadTransformTranslate(TiXmlElement* element, RTMatrix44& out)const
	{
		RTVector3f translationV;
		getVector3(element, translationV);
		out.createTranslation(translationV.x, translationV.y, translationV.z);
	}

	void RTSceneLoader::loadTransformScale(TiXmlElement* element, RTMatrix44& out)const
	{
		string type = element->Attribute("type");
		if(type.compare("uniform") == 0)
		{
			F32 s = getFloat(element);
			out.createScale(s);
		}
		else
		{
			RTVector3f s;
			getVector3(element, s);
			out.createScale(s);
		}
	}

	void RTSceneLoader::loadProcTextureChecker(TiXmlElement* element, RTMaterial* material)const
	{
		RTColor color[2];
		F32 length=0;
		RTVector3f map;

		//transformation matrices
		RTMatrix44 T, R, S;
		T.identity(); R.identity(); S.identity();

		TiXmlElement* parameter = element->FirstChildElement();
		while(parameter != 0)
		{
			RTMatrix44 temp;
			string paramName = parameter->Value();

			if(paramName.compare("Color1") == 0)
				getVector3(parameter, color[0]);
			else if(paramName.compare("Color2") == 0)
				getVector3(parameter, color[1]);
			else if(paramName.compare("Length") == 0)
				length = getFloat(parameter);
			else if(paramName.compare("Map") == 0)
				getVector3(parameter, map);
			else if(paramName.compare("Translate")==0)
			{
				loadTransformTranslate(parameter, temp);
				T = T * temp;
			}
			else if(paramName.compare("Rotate")==0)
			{
				loadTransformRotation(parameter, temp);
				R = R * temp;
			}
			else if(paramName.compare("Scale")==0)
			{
				loadTransformScale(parameter, temp);
				S = S * temp;
			}

			parameter = parameter->NextSiblingElement();
		}

		RTProcTextureChecker* texture = new RTProcTextureChecker(color, length, map);
		texture->setMatrices(T, R, S);
		//material->setProcTexture(texture);
		material->setAmbient(texture);
		material->setDiffuse(texture);
		//SCENE.addTexture(texture);
	}

	void RTSceneLoader::loadProcTextureWood(TiXmlElement* element, RTMaterial* material)const
	{
		F32 persistance = 0;
		F32 treshold = 0;
		I32 octave = 0;

		RTMatrix44 T, R, S;
		T.identity(); R.identity(); S.identity();

		TiXmlElement* parameter = element->FirstChildElement();
		while(parameter != 0)
		{
			RTMatrix44 temp;
			string paramName = parameter->Value();

			if(paramName.compare("Persistance") == 0)
				persistance = getFloat(parameter);
			else if(paramName.compare("Threshold") == 0)
				treshold = getFloat(parameter);
			else if(paramName.compare("Octave") == 0)
				octave = (I32)getFloat(parameter);
			else if(paramName.compare("Translate")==0)
			{
				loadTransformTranslate(parameter, temp);
				T = T * temp;
			}
			else if(paramName.compare("Rotate")==0)
			{
				loadTransformRotation(parameter, temp);
				R = R * temp;
			}
			else if(paramName.compare("Scale")==0)
			{
				loadTransformScale(parameter, temp);
				S = S * temp;
			}

			parameter = parameter->NextSiblingElement();
		}

		RTProcTextureWood* texture = new RTProcTextureWood(persistance, octave, treshold);
		texture->setMatrices(T, R, S);
		//material->setProcTexture(texture);
		material->setAmbient(texture);
		material->setDiffuse(texture);
		//SCENE.addTexture(texture);
	}

	void RTSceneLoader::loadProcTextureMarble(TiXmlElement* element, RTMaterial* material)const
	{
		F32 persistance = 0;
		I32 octave = 0;

		RTMatrix44 T, R, S;
		T.identity(); R.identity(); S.identity();

		TiXmlElement* parameter = element->FirstChildElement();
		while(parameter != 0)
		{
			RTMatrix44 temp;
			string paramName = parameter->Value();

			if(paramName.compare("Persistance") == 0)
				persistance = getFloat(parameter);
			else if(paramName.compare("Octave") == 0)
				octave = (I32)getFloat(parameter);
			else if(paramName.compare("Translate")==0)
			{
				loadTransformTranslate(parameter, temp);
				T = T * temp;
			}
			else if(paramName.compare("Rotate")==0)
			{
				loadTransformRotation(parameter, temp);
				R = R * temp;
			}
			else if(paramName.compare("Scale")==0)
			{
				loadTransformScale(parameter, temp);
				S = S * temp;
			}

			parameter = parameter->NextSiblingElement();
		}

		RTProcTextureMarble* texture = new RTProcTextureMarble(persistance, octave);
		texture->setMatrices(T, R, S);
		//material->setProcTexture(texture);
		material->setAmbient(texture);
		material->setDiffuse(texture);
		//SCENE.addTexture(texture);
	}

	void RTSceneLoader::loadProcTextureThreshold(TiXmlElement* element, RTMaterial* material)const
	{
		F32 threshold;
		RTColor c;

		stringstream ss;

		RTMatrix44 T, R, S;
		T.identity(); R.identity(); S.identity();

		RTProcTextureThreshold* texture = new RTProcTextureThreshold();

		TiXmlElement* parameter = element->FirstChildElement();
		while(parameter != 0)
		{
			RTMatrix44 temp;
			string paramName = parameter->Value();

			if(paramName.compare("Persistance") == 0)
				texture->setPersistance(getFloat(parameter));
			else if(paramName.compare("Octave") == 0)
				texture->setOctave( (I32)getFloat(parameter));
			else if(paramName.compare("Intensity") == 0)
				texture->setIntensity( getFloat(parameter));
			else if(paramName.compare("Threshold") == 0)
			{
				ss.flush();
				ss.clear();
				ss << parameter->Attribute("value");
				ss >> threshold;
				getVector3(parameter, c);
				texture->addThreshold(threshold, c);
			}
			else if(paramName.compare("Translate")==0)
			{
				loadTransformTranslate(parameter, temp);
				T = T * temp;
			}
			else if(paramName.compare("Rotate")==0)
			{
				loadTransformRotation(parameter, temp);
				R = R * temp;
			}
			else if(paramName.compare("Scale")==0)
			{
				loadTransformScale(parameter, temp);
				S = S * temp;
			}
			
			parameter = parameter->NextSiblingElement();
		}

		texture->setMatrices(T, R, S);
		//material->setProcTexture(texture);
		material->setAmbient(texture);
		material->setDiffuse(texture);
		//SCENE.addTexture(texture);
	}

	void RTSceneLoader::loadProcTextureBump(TiXmlElement* element, RTMaterial* material)const
	{
		F32 persistance = 0;
		F32 I32ensity = 0;
		I32 octave = 0;

		RTMatrix44 T, R, S;
		T.identity(); R.identity(); S.identity();

		TiXmlElement* parameter = element->FirstChildElement();
		while(parameter != 0)
		{
			RTMatrix44 temp;

			string paramName = parameter->Value();

			if(paramName.compare("Persistance") == 0)
				persistance = getFloat(parameter);
			else if(paramName.compare("Octave") == 0)
				octave = (I32)getFloat(parameter);
			else if(paramName.compare("Intensity") == 0)
				I32ensity = getFloat(parameter);
			else if(paramName.compare("Translate")==0)
			{
				loadTransformTranslate(parameter, temp);
				T = T * temp;
			}
			else if(paramName.compare("Rotate")==0)
			{
				loadTransformRotation(parameter, temp);
				R = R * temp;
			}
			else if(paramName.compare("Scale")==0)
			{
				loadTransformScale(parameter, temp);
				S = S * temp;
			}

			parameter = parameter->NextSiblingElement();
		}

	
		RTProcTextureBump* texture = new RTProcTextureBump(persistance, octave, I32ensity);
		texture->setMatrices(T, R, S);
		material->setBumpMap(texture);
		//SCENE.addTexture(texture);
	}

	void RTSceneLoader::getVector3(TiXmlElement* position, RTVector3f& vector3)const
	{
		stringstream ss;
		ss<<position->GetText();
		ss>>vector3.x;
		ss>>vector3.y;
		ss>>vector3.z;
	}

	void RTSceneLoader::getVector3(TiXmlElement* position, RTVector4f& vector4)const
	{
		stringstream ss;
		ss<<position->GetText();
		ss>>vector4.RTVEC4X;
		ss>>vector4.RTVEC4Y;
		ss>>vector4.RTVEC4Z;
		vector4.RTVEC4W = 0;
	}

	F32 RTSceneLoader::getFloat(TiXmlElement* element)const
	{
		stringstream ss;
		ss<<element->GetText();
		F32 f;
		ss>>f;
		return f;
	}

}